"""
Case Type   : 故障&可靠性测试
Case Name   : most_available_sync=on时，restore过程中停止备节点
Create At   : 2020/11/23
Owner       : @zou_jialiang0505328126
Description :
    1.配置most_available_sync=on
    2.恢复数据
    3.恢复数据过程中停止所有备节点
    4.检查恢复前后数据是否一致
Expect      :
    1.若不为on则重新设置，重启数据库生效
    2.恢复数据成功
    3.停止备节点成功
    4.恢复前后数据一样，无表丢失
History     :
    modified: 2020/03/01  modified by @peilinqian,修改创建数据库SQL；以防已存在库导致断言失败
    modified: 2021/03/01  modified by @peilinqian,进行删除预设数据后，等待主备同步；删除teardown断言
    modified: 2020/12/10  modified by @wan005,修改恢复数据库为新创建数据库，防止恢复失败导致后续用例失败
    modified: 2021/01/08  modified by @wan005,物化视图不支持compression等参数，修改断言适配1.1.0版本
    modified: 2021/07/05  modified by @wan005,创建前增加删除数据库,确保创建成功
"""

import os
import unittest
import time
from yat.test import macro
from yat.test import Node
import sys

sys.path.append(sys.path[0] + "/../")
from testcase.utils.CommonSH import *
from testcase.utils.Common import Common
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from testcase.utils.ComThread import ComThread
Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(1 == Primary_SH.get_node_num(), '单机环境不执行')
class Basebackup(unittest.TestCase):
    commonshsta = CommonSH('Standby1DbUser')
    commonshsta2 = CommonSH('Standby2DbUser')
    nodes_tuple = ('PrimaryDbUser', 'Standby1DbUser', 'Standby2DbUser')

    @RestartDbCluster(*nodes_tuple)
    def setUp(self):
        self.log = Logger()
        self.log.info('------------Opengauss_Reliability_Tools_Restore_Case003.py 开始执行------------')
        self.dbPrimaryDbUser = Node(node='PrimaryDbUser')
        self.dbStandby1DbUser = Node(node='Standby1DbUser')
        self.dbStandby2DbUser = Node(node='Standby2DbUser')
        self.Constant = Constant()
        self.common = Common('PrimaryRoot')
        self.restore_file = os.path.join(macro.DB_BACKUP_PATH, 'dump_backup', 'tools_restore_case001.tar')
        self.sql_path = os.path.join(macro.DB_BACKUP_PATH, 'testscript')
        self.resotreGuc = False
        self.synchronous_commit = False

        status = Primary_SH.getDbClusterStatus()
        self.log.info(status)
        self.assertTrue("Degraded" in status or "Normal" in status)

        self.log.info('-------------------创建备份路径-----------------------------------')
        shell_cmd = f'rm -rf {os.path.dirname(self.restore_file)}; mkdir {os.path.dirname(self.restore_file)}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info('-----------------------生成预设数据-----------------------')
        result = self.common.scp_file(self.dbPrimaryDbUser, 'restore_data.sql', self.sql_path)
        self.log.info(result)
        sql_file_cmd = f'''
                            source {macro.DB_ENV_PATH};
                            gsql -d {self.dbPrimaryDbUser.db_name} -p {self.dbPrimaryDbUser.db_port}  -f {os.path.join(
            self.sql_path, 'restore_data.sql')}'''
        self.log.info(sql_file_cmd)
        sql_bx_msg = self.dbPrimaryDbUser.sh(sql_file_cmd).result()
        self.log.info(sql_bx_msg)
        self.assertNotIn('ERROR', sql_bx_msg)

        self.log.info('--------------------获取还原前数据库已有表------------------------')
        self.table_list = Primary_SH.executDbSql(r'\d')
        self.log.info(self.table_list)

        self.log.info('--------------------导出数据----------------------------')
        result = Primary_SH.dumpFile(filename=self.restore_file,
                                     get_detail=False)
        self.log.info(result)
        self.assertTrue(result)

        self.dbname = 'dbsys_restore_db'
        self.log.info("---------------------创建数据库--------------------")
        result = Primary_SH.executDbSql(f'drop database '
            f'if exists {self.dbname};'
            f'create database {self.dbname};')
        self.log.info(result)
        self.assertIn(self.Constant.CREATE_DATABASE_SUCCESS_MSG, result)

        self.log.info('------------------------设置synchronous_commit=on---------------')
        result = Primary_SH.executeGsguc('check',
                                         'synchronous_commit=on',
                                         'synchronous_commit')
        if not result:
            self.synchronous_commit = True
            result = Primary_SH.executDbSql('show synchronous_commit')
            self.log.info(result)
            self.synchronous_commit_vaule = result.splitlines()[2]
            result = Primary_SH.executeGsguc('set',
                                             self.Constant.GSGUC_SUCCESS_MSG,
                                             'synchronous_commit=on')
            self.assertTrue(result)

    def test_basebackup(self):
        self.log.info('--------------------设置most_available_sync=on----------------------')
        result = Primary_SH.executeGsguc('check',
                                         'most_available_sync=on',
                                         'most_available_sync')
        if not result:
            self.resotreGuc = True
            result = Primary_SH.executeGsguc('set',
                                             self.Constant.GSGUC_SUCCESS_MSG,
                                             'most_available_sync=on')
            self.assertTrue(result)
            result = Primary_SH.stopDbCluster()
            self.assertTrue(result)
            result = Primary_SH.startDbCluster()
            self.assertTrue(result)

        self.log.info('------------------起线程恢复数据-----------------------------------')
        restore_thread = ComThread(Primary_SH.restoreFile,
                                   args=(self.restore_file,
                                         '-c',
                                         True,
                                         self.dbname))
        restore_thread.setDaemon(True)
        restore_thread.start()

        self.log.info('--------------------------停止备节点------------------------------')
        result = self.commonshsta.stopDbInstance()
        self.log.info(result)
        self.assertIn(self.Constant.GS_CTL_STOP_SUCCESS_MSG, result)
        result = self.commonshsta2.stopDbInstance()
        self.log.info(result)
        self.assertIn(self.Constant.GS_CTL_STOP_SUCCESS_MSG, result)

        self.log.info('-------------------------检查恢复数据结果------------------------')
        restore_thread.join(60 * 60)
        result = restore_thread.get_result()
        self.assertIn(self.Constant.RESTORE_SUCCESS_MSG, result)

        self.log.info('----------------------------对比恢复前后数据是否一致-------------------------')
        time.sleep(5)
        self.table_list_after = Primary_SH.executDbSql(r'\d', dbname=self.dbname)
        self.log.info(self.table_list_after)
        self.assertIn(self.table_list, self.table_list_after)

    def tearDown(self):
        self.log.info('-------------------------环境清理------------------------')
        self.log.info('--------------------------启动备节点------------------------------')
        result = self.commonshsta.startDbInstance('standby')
        self.log.info(result)
        result = self.commonshsta2.startDbInstance('standby')
        self.log.info(result)

        self.log.info('--------------------------删除备份文件------------------')
        shell_cmd = f'rm -rf {os.path.dirname(self.restore_file)}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info('--------------------------删除预设数据---------------------')
        result = self.common.scp_file(self.dbPrimaryDbUser, 'clear_restore_data.sql', self.sql_path)
        self.log.info(result)
        sql_file_cmd = f'''
                                       source {macro.DB_ENV_PATH};
                                       gsql -d {self.dbPrimaryDbUser.db_name} -p {self.dbPrimaryDbUser.db_port}  -f {os.path.join(
            self.sql_path, 'clear_restore_data.sql')}
        '''
        self.log.info(sql_file_cmd)
        sql_bx_msg = self.dbPrimaryDbUser.sh(sql_file_cmd).result()
        self.log.info(sql_bx_msg)

        self.log.info('----------------------删除执行脚本路径----------------------------')
        shell_cmd = f'rm -rf {self.sql_path}'
        self.log.info(shell_cmd)
        result = self.dbPrimaryDbUser.sh(shell_cmd).result()
        self.log.info(result)

        self.log.info('----查看主机query，同步是否正常----')
        Primary_SH.check_location_consistency('primary', 3)

        self.log.info('----查询主备状态----')
        Primary_SH.getDbClusterStatus('status')

        # 自动化执行时可能配置该参数为on
        self.log.info('------------------------------还原most_available_sync配置-----------------------')
        if self.resotreGuc:
            Primary_SH.executeGsguc('set',
                                    self.Constant.GSGUC_SUCCESS_MSG,
                                    'most_available_sync=off')
            Primary_SH.stopDbCluster()
            Primary_SH.startDbCluster()

        if self.synchronous_commit:
            Primary_SH.executeGsguc('set',
                                    self.Constant.GSGUC_SUCCESS_MSG,
                                    f'synchronous_commit='
                                    f'{self.synchronous_commit_vaule}')
            Primary_SH.stopDbCluster()
            Primary_SH.startDbCluster()

        self.log.info('----------------------检查备机是否需要重建---------------------------')
        result = Primary_SH.check_whether_need_build()
        if result:
            self.commonshsta.executeGsctl('build', self.Constant.BUILD_SUCCESS_MSG)
            self.commonshsta2.executeGsctl('build', self.Constant.BUILD_SUCCESS_MSG)

        self.log.info("---------------------drop database--------------------")
        result = Primary_SH.executDbSql(f'drop database {self.dbname};')
        self.log.info(result)
        self.log.info('----------Opengauss_Reliability_Tools_Restore_Case003.py 执行结束-----------------------')
